package cn.hcbycloud.common.async.aop;

import cn.hcbycloud.common.async.annotation.AsyncTask;
import cn.hcbycloud.common.async.constant.AsyncTaskStatusEnum;
import cn.hcbycloud.common.async.service.AsyncTaskManagerService;
import cn.hcbycloud.common.async.service.pool.IThreadPoolService;
import cn.hcbycloud.common.async.vo.AsyncTaskInfo;
import cn.hcbycloud.common.core.utils.DateUtils;
import cn.hcbycloud.common.redis.utils.RedisOperator;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.stereotype.Component;

import java.time.LocalDateTime;

/**
 * @author gaoh
 * @desc 异步任务执行监控切面
 * @date 2022年02月07日 上午 11:32
 */
@Slf4j
@Aspect
@Component
@AllArgsConstructor
public class AsyncTaskMonitor {
    /**
     * 异步任务存入redis，默认存储48小时
     */
    private static final long EXPIRE_TIME = 2* 24 * 3600L;
    /**
     * 异步任务管理器
     */
    AsyncTaskManagerService asyncTaskManagerService;
    /**
     * redis操作接口
     */
    RedisOperator redisOperator;
    /**
     * 异步任务线程配置接口
     */
    IThreadPoolService threadPoolService;
    /**
     * 切入点
     */
    @Pointcut(value = "@annotation(cn.hcbycloud.common.async.annotation.AsyncTask)")
    private void taskHandle() {

    }


    @Around("taskHandle()")
    public Object around(ProceedingJoinPoint pjp){
        Signature signature = pjp.getSignature();
        String className = pjp.getTarget().getClass().getSimpleName();
        String methodName = signature.getName();
        // 获取 taskId, 调用异步任务传入的第一个参数
        String taskId = pjp.getArgs()[0].toString();
        // 获取任务信息, 在提交任务的时候就已经放入到容器中了
        AsyncTaskInfo taskInfo = asyncTaskManagerService.getTaskInfo(taskId);
        taskInfo.setStatus(AsyncTaskStatusEnum.RUNNING);
        // 设置为运行状态, 并重新放入容器
        asyncTaskManagerService.setTaskInfo(taskInfo);
        AsyncTaskStatusEnum status;
        Object result;
        String exceptionMessage="";
        try {
            // 执行异步任务
            result = pjp.proceed();
            status = AsyncTaskStatusEnum.SUCCESS;
        } catch (Throwable ex) {
            // 异步任务出现了异常
            result = null;
            status = AsyncTaskStatusEnum.FAILED;
            exceptionMessage=ex.getMessage();
            log.error("AsyncTaskMonitor: async task [{}] is failed, Error Info: [{}]",
                    taskId, ex.getMessage(), ex);
        }
        // 设置异步任务其他的信息, 再次重新放入到容器中
        taskInfo.setEndTime(LocalDateTime.now());
        taskInfo.setStatus(status);
        taskInfo.setTotalTime(String.valueOf(DateUtils.betweenTwoTime(taskInfo.getEndTime(),
                taskInfo.getStartTime())));
        taskInfo.setExceptionMessage(exceptionMessage);
        taskInfo.setClassName(className);
        taskInfo.setMethodName(methodName);
        taskInfo.setTenantCode(threadPoolService.getTaskLogInfoPrefix());
        asyncTaskManagerService.setTaskInfo(taskInfo);
        log.info("AsyncTaskInfo:{}",asyncTaskManagerService.getTaskInfo(taskId));
        redisOperator.setObject(threadPoolService.getRedisIndex(),threadPoolService.getTaskLogInfoPrefix()+"-"+className+"-"+taskId,
                asyncTaskManagerService.getTaskInfo(taskId),EXPIRE_TIME);
        return result;
    }
}